package cn.keniykey.mc.landterritory.landflag;

import java.io.InputStream;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import javax.annotation.Nullable;

import org.bukkit.plugin.InvalidDescriptionException;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.AbstractConstruct;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.Tag;

import com.google.common.collect.ImmutableSet;

/**
 * 领地标记Jar中的landflag.yml内容
 */
public final class LandFlagDescription {
	private static final ThreadLocal<Yaml> thread_yaml;
	private static final Pattern pattern_name,pattern_int,pattern_game_version;
	private String main; //main文件
	private String name; //标记识别名
	private int version; //标记版本
	private int api_version; //最低api版本
	private Set<String> conflict_flag; //冲突标记
	private Set<String> preposition_plugin; //前置插件
	private String game_version; //需求游戏版本
	
	static {
		pattern_name = Pattern.compile("^[A-Za-z0-9_-]+$");
		pattern_int = Pattern.compile("^\\d+$");
		pattern_game_version = Pattern.compile("^\\d{1,2}(\\.\\d{1,2}){1,3}$");
		thread_yaml = new ThreadLocal<Yaml>() {
			@Override
			protected Yaml initialValue() {
				return new Yaml(new SafeConstructor() {
					{
						this.yamlConstructors.put(null, new AbstractConstruct() {
							@Override
							public Object construct(Node node) {
								if(!node.getTag().startsWith("!@")) {
									return SafeConstructor.undefinedConstructor.construct(node);
								}
								return node.toString();
							}
						});
						this.yamlConstructors.put(new Tag("!@UTF8"), new AbstractConstruct() {
							@Override
							public Object construct(Node node) {
								return "UTF8";
							}
						});
					}
				});
			}
		};
	}
	
	private LandFlagDescription() {
		this.api_version = LandFlagManager.API_VERSION;
		this.conflict_flag = Collections.emptySet();
		this.preposition_plugin = Collections.emptySet();
	}
	LandFlagDescription(final InputStream steam) throws InvalidDescriptionException {
		this();
		this.loadByMap(this.castMap(thread_yaml.get().load(steam)));
	}
	public LandFlagDescription(String main,String name) {
		this(main,name,(Integer.MAX_VALUE-1),null);
	}
	public LandFlagDescription(String main,String name,int ver,@Nullable Set<String> conflict_flags){
		this();
		this.main = main;
		this.name = name; 
		this.version = ver;
		if(conflict_flags != null && !conflict_flags.isEmpty()) this.conflict_flag = Collections.unmodifiableSet(conflict_flags);
	}
	
	private Map<?,?> castMap(Object obj) throws InvalidDescriptionException {
		if(obj instanceof Map) return (Map<?,?>)obj;
		throw new InvalidDescriptionException(obj.toString() + " 结构错误");
	}
	private void loadByMap(Map<?,?> dermap) throws InvalidDescriptionException {
		try {
			this.name = dermap.get("name").toString();
			if(!pattern_name.matcher(this.name).matches()) {
				throw new InvalidDescriptionException("name " + this.name + " 不符合要求");
			}
		}catch(InvalidDescriptionException ie) {
			throw ie;
		}catch(Exception ex) {
			throw new InvalidDescriptionException(ex,"name " + ex.getMessage());
		}
		try {
			this.main = dermap.get("main").toString();
			if(this.main.startsWith("cn.freekingke.landterritory") || this.main.startsWith("cn.freekingke.library")
					|| this.main.startsWith("net.minecraft") || this.main.startsWith("org.bukkit")) {
				throw new InvalidDescriptionException("main " + this.main + " 属于违规名");
			}
		}catch(InvalidDescriptionException ie) {
			throw ie;
		}catch(Exception ex) {
			throw new InvalidDescriptionException(ex,"main " + ex.getMessage());
		}
		try {
			if(dermap.containsKey("version")) {
				final String ver_str = dermap.get("version").toString();
				if(!pattern_int.matcher(ver_str).matches()) {
					throw new InvalidDescriptionException("version " + ver_str + " 必须是纯数字");
				}
				this.version = Integer.valueOf(ver_str);
				if(this.version < 0) {
					throw new InvalidDescriptionException("version " + ver_str + " 超出Int最大值 " + Integer.MAX_VALUE);
				}
			}
		}catch(InvalidDescriptionException ie) {
			throw ie;
		}catch(Exception ex) {
			throw new InvalidDescriptionException(ex,"version " + ex.getMessage());
		}
		try {
			if(dermap.containsKey("api_version")) {
				final String str = dermap.get("api_version").toString();
				if(!pattern_int.matcher(str).matches()) {
					throw new InvalidDescriptionException("api_version " + str + " 必须是纯数字");
				}
				this.api_version = Integer.valueOf(str);
				if(this.api_version < 0) {
					throw new InvalidDescriptionException("api_version " + str + " 超出Int最大值 " + Integer.MAX_VALUE);
				}
			}
		}catch(InvalidDescriptionException ie) {
			throw ie;
		}catch(Exception ex) {
			throw new InvalidDescriptionException(ex, "api_version " + ex.getMessage());
		}
		try {
			if(dermap.containsKey("conflict_flag")) {
				final ImmutableSet.Builder<String> str_set = ImmutableSet.builder();
				for(final Object obj : (Iterable<?>)dermap.get("conflict_flag")) {
					final String str = obj.toString();
					if(this.name.equals(str)) throw new InvalidDescriptionException("conflict_flag " + str + " 不应该出现");
					str_set.add(str);
				}
				this.conflict_flag = str_set.build();
			}
		}catch(InvalidDescriptionException ie) {
			throw ie;
		}catch(Exception ex) {
			throw new InvalidDescriptionException(ex, "conflict_flag " + ex.getMessage());
		}
		try {
			if(dermap.containsKey("preposition_plugin")) {
				final ImmutableSet.Builder<String> str_set = ImmutableSet.builder();
				for(final Object obj : (Iterable<?>)dermap.get("preposition_plugin")) {
					str_set.add(obj.toString());
				}
				this.preposition_plugin = str_set.build();
			}
		}catch(Exception ex) {
			throw new InvalidDescriptionException(ex, "preposition_plugin " + ex.getMessage());
		}
		try {
			if(dermap.containsKey("game_version")) {
				this.game_version = dermap.get("game_version").toString();
				if(!pattern_game_version.matcher(this.game_version).matches()) {
					throw new InvalidDescriptionException("game_version " + this.game_version + " 不符合规范xx(.xx){,3}");
				}
			}
		}catch(InvalidDescriptionException ie) {
			throw ie;
		}catch(Exception ex) {
			throw new InvalidDescriptionException(ex, "game_version " + ex.getMessage());
		}
	}
	
	public String getMain() {
		return this.main;
	}
	public String getName() {
		return this.name;
	}
	public int getVersion() {
		return this.version;
	}
	public int getAPIVersion() {
		return this.api_version;
	}
	@Nullable
	public String getGameVersion() {
		return this.game_version;
	}
	public Set<String> getConflictFlag() {
		return this.conflict_flag;
	}
	public Set<String> getPrepositionPlugin() {
		return this.preposition_plugin;
	}
}